﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using System.ComponentModel;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace Jemgine.Data
{
        [Jemgine.Engine.Category("Primitive"), Jemgine.Engine.Component]
	public partial class Circle : EntityElement, EditorDrawable, Translatable, Scalable, ReferenceTarget, Engine.Renderer.IDrawable
	{
        public int BoneID { get; set; }
        [ContentSerializerIgnore]
        public Bone BoneReference { get; set; }

		public Engine.GeometryType Type { get; set; }
        public Vector4 Color { get; set; }
        public int Segments { get; set; }
        public float Radius { get; set; }
        public Vector2 Position { get; set; }

        public TextureAlignment Alignment { get; set; }
        [System.ComponentModel.Editor(typeof(TextureEditor), typeof(System.Drawing.Design.UITypeEditor))]
        public String Texture { get; set; }


		public Circle(Circle c)
		{
            Type = c.Type;
            Color = c.Color;
            Segments = c.Segments;
            Radius = c.Radius;
            Position = c.Position;
            BoneID = c.BoneID;
            Texture = c.Texture;
            Alignment = c.Alignment.Clone();
		}

		public Circle()
		{
			Type = Engine.GeometryType.Both;
            Color = Vector4.One;
            Segments = 16;
            Radius = 8;
            Alignment = new TextureAlignment();
        }

        [ContentSerializerIgnore]
        internal VertexPositionTexture[] DecomposedCache = null;

        internal void UpdateDecomposedCache()
        {
            var Verts = GetVerticies();
            DecomposedCache = new VertexPositionTexture[Verts.Length];
            var TextureMatrix = Alignment.GetMatrix();

            int StartV = 0;
            int EndV = Verts.Length - 1;
            int BufferPos = 0;

            while (StartV <= EndV)
            {
                DecomposedCache[BufferPos].Position = new Vector3(Verts[StartV] + Position, 0.0f);
                DecomposedCache[BufferPos].TextureCoordinate =
                    Vector2.Transform(Verts[StartV] + Position, TextureMatrix);
               
                ++BufferPos;
                if (StartV != EndV)
                {
                    DecomposedCache[BufferPos].Position = new Vector3(Verts[EndV] + Position, 0.0f);
                    DecomposedCache[BufferPos].TextureCoordinate =
                        Vector2.Transform(Verts[EndV] + Position, TextureMatrix); 
                    ++BufferPos;
                }
                ++StartV;
                --EndV;
            }  
        }

        public Vector2[] GetVerticies()
        {
            var R = new Vector2[Segments];

            Vector2 StartPoint = new Vector2(0, Radius);
            Matrix Rot = Matrix.CreateRotationZ(MathHelper.ToRadians(360.0f / (float)Segments));

            for (int i = 0; i < Segments; ++i)
            {
                R[i] = StartPoint + Position;
                StartPoint = Vector2.Transform(StartPoint, Rot);
            }

            return R;
        }

        [Microsoft.Xna.Framework.Content.ContentSerializerIgnore]
        public int ReferenceID { get; set; }

        public Vector2 GetWorldPosition()
        {
            if (Owner == null) return Position;
            else return Owner.Position + Position;
        }

        [Microsoft.Xna.Framework.Content.ContentSerializerIgnore]
        public EntityRecord Owner { get; private set; }

        public void SetOwner(EntityRecord E)
        {
            Owner = E;
        }

        #region EntityElementMembers

        public bool PointInside(Vector2 Point)
        {
            if ((Position - Point).Length() <= Radius) return true;
            return false;
        }

        public Engine.Selection.Types SelectionType()
        {
            return Jemgine.Engine.Selection.Types.EntityElement;
            //return Jemgine.Engine.Selection.Types.Circle;
        }
        public EntityElement Clone() { return new Circle(this); }
        public void Initialize(EntityRecord Owner, Microsoft.Xna.Framework.Content.ContentManager Content) { }
        public void Destroy() { }
        public void ApplyTextureOffset(int Offset) { }
        public void MarkUsedTextures(int[] TextureReferenceCounts) { }
        public void RemapTextures(List<String> OT, List<String> NT) { }
        #endregion

        #region EditorDrawable Members

        public void Draw(int ID, EditorDrawData Context, SelectionType Selected)
        {
            Context.Renderer.Color = EditorDrawData.DrawColor(Selected);
            Context.Renderer.DrawCircle(this);
        }

        #endregion

        #region Translatable Members

        object Translatable.PrepareToTranslate()
        {
            return Position;
        }

        void Translatable.ApplyTranslation(object Tag, Vector2 MouseDelta)
        {
            Vector2 OriginalPosition = (Vector2)Tag;
            Position = OriginalPosition + MouseDelta;
            DecomposedCache = null;
        }

        void Translatable.Snap(Snapper Snapper)
        {
            Position = Snapper.SnapPosition(Position);
            DecomposedCache = null;
        }

        #endregion

        #region Scalable Members

        object Scalable.PrepareToScale()
        {
            return Radius;
        }

        void Scalable.ApplyScale(object Tag, float Delta)
        {
            Radius = (float)Tag + Delta;
            DecomposedCache = null;
        }

        void Scalable.Snap(Snapper Snapper)
        {
            Radius = Snapper.SnapScale(Radius);
            DecomposedCache = null;
        }

        #endregion


        void Engine.Renderer.IDrawable.Draw(
            Engine.Renderer.RenderEffect Effect,
            Engine.Renderer.VertexPusher Pusher, 
            Engine.EpisodeContentManager Content)
        {
            if (DecomposedCache == null) UpdateDecomposedCache();
            Effect.Color = Color;
            Effect.Texture = Content.GetTexture(Texture);
            Pusher.DrawTriangleStrip(DecomposedCache);
        }
    }
}
